home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / amiga / plotting / gnuplot3.lzh / gnuplot / graphics.c < prev    next >
C/C++ Source or Header  |  1991-09-09  |  42KB  |  1,563 lines

  1. /* GNUPLOT - graphics.c */
  2. /*
  3.  * Copyright (C) 1986, 1987, 1990, 1991   Thomas Williams, Colin Kelley
  4.  *
  5.  * Permission to use, copy, and distribute this software and its
  6.  * documentation for any purpose with or without fee is hereby granted, 
  7.  * provided that the above copyright notice appear in all copies and 
  8.  * that both that copyright notice and this permission notice appear 
  9.  * in supporting documentation.
  10.  *
  11.  * Permission to modify the software is granted, but not the right to
  12.  * distribute the modified code.  Modifications are to be distributed 
  13.  * as patches to released version.
  14.  *  
  15.  * This software is provided "as is" without express or implied warranty.
  16.  * 
  17.  *
  18.  * AUTHORS
  19.  * 
  20.  *   Original Software:
  21.  *     Thomas Williams,  Colin Kelley.
  22.  * 
  23.  *   Gnuplot 2.0 additions:
  24.  *       Russell Lang, Dave Kotz, John Campbell.
  25.  *
  26.  *   Gnuplot 3.0 additions:
  27.  *       Gershon Elber and many others.
  28.  * 
  29.  * Send your comments or suggestions to 
  30.  *  pixar!info-gnuplot@sun.com.
  31.  * This is a mailing list; to join it send a note to 
  32.  *  pixar!info-gnuplot-request@sun.com.  
  33.  * Send bug reports to
  34.  *  pixar!bug-gnuplot@sun.com.
  35.  */
  36.  
  37. #include <stdio.h>
  38. #include <math.h>
  39. #include <assert.h>
  40. #include <time.h>
  41. #include "plot.h"
  42. #include "setshow.h"
  43.  
  44. extern char *strcpy(),*strncpy(),*strcat(),*ctime();
  45. char *tdate;
  46. #ifdef AMIGA_AC_5
  47. time_t dated;
  48. #else
  49. #ifdef VMS
  50. time_t dated,time();
  51. #else
  52. long dated,time();
  53. #endif
  54. #endif
  55.  
  56. void plot_impulses();
  57. void plot_lines();
  58. void plot_points();
  59. void plot_dots();
  60. void plot_bars();
  61. void edge_intersect();
  62. BOOLEAN two_edge_intersect();
  63.  
  64. /* for plotting error bars */
  65. #define ERRORBARTIC (t->h_tic/2) /* half the width of error bar tic mark */
  66.  
  67. #ifndef max        /* Lattice C has max() in math.h, but shouldn't! */
  68. #define max(a,b) ((a > b) ? a : b)
  69. #endif
  70.  
  71. #ifndef min
  72. #define min(a,b) ((a < b) ? a : b)
  73. #endif
  74.  
  75. #define inrange(z,min,max) ((min<max) ? ((z>=min)&&(z<=max)) : ((z>=max)&&(z<=min)) )
  76.  
  77. /* True if a and b have the same sign or zero (positive or negative) */
  78. #define samesign(a,b) ((a) * (b) >= 0)
  79.  
  80. /* Define the boundary of the plot
  81.  * These are computed at each call to do_plot, and are constant over
  82.  * the period of one do_plot. They actually only change when the term
  83.  * type changes and when the 'set size' factors change. 
  84.  */
  85. static int xleft, xright, ybot, ytop;
  86.  
  87. /* Boundary and scale factors, in user coordinates */
  88. /* x_min, x_max, y_min, y_max are local to this file and
  89.  * are not the same as variables of the same names in other files
  90.  */
  91. static double x_min, x_max, y_min, y_max;
  92. static double xscale, yscale;
  93.  
  94. /* And the functions to map from user to terminal coordinates */
  95. #define map_x(x) (int)(xleft+(x-x_min)*xscale+0.5) /* maps floating point x to screen */ 
  96. #define map_y(y) (int)(ybot+(y-y_min)*yscale+0.5)    /* same for y */
  97.  
  98. /* (DFK) Watch for cancellation error near zero on axes labels */
  99. #define SIGNIF (0.01)        /* less than one hundredth of a tic mark */
  100. #define CheckZero(x,tic) (fabs(x) < ((tic) * SIGNIF) ? 0.0 : (x))
  101. #define NearlyEqual(x,y,tic) (fabs((x)-(y)) < ((tic) * SIGNIF))
  102.  
  103. /* (DFK) For some reason, the Sun386i compiler screws up with the CheckLog 
  104.  * macro, so I write it as a function on that machine.
  105.  */
  106. #ifndef sun386
  107. /* (DFK) Use 10^x if logscale is in effect, else x */
  108. #define CheckLog(log, x) ((log) ? pow(10., (x)) : (x))
  109. #else
  110. static double
  111. CheckLog(log, x)
  112.      BOOLEAN log;
  113.      double x;
  114. {
  115.   if (log)
  116.     return(pow(10., x));
  117.   else
  118.     return(x);
  119. }
  120. #endif /* sun386 */
  121.  
  122. double
  123. LogScale(coord, islog, what, axis)
  124.     double coord;            /* the value */
  125.     BOOLEAN islog;            /* is this axis in logscale? */
  126.     char *what;            /* what is the coord for? */
  127.     char *axis;            /* which axis is this for ("x" or "y")? */
  128. {
  129.     if (islog) {
  130.        if (coord <= 0.0) {
  131.           char errbuf[100];        /* place to write error message */
  132.         (void) sprintf(errbuf,"%s has %s coord of %g; must be above 0 for log scale!",
  133.                 what, axis, coord);
  134.           (*term_tbl[term].text)();
  135.           (void) fflush(outfile);
  136.           int_error(errbuf, NO_CARET);
  137.        } else
  138.         return(log10(coord));
  139.     }
  140.     return(coord);
  141. }
  142.  
  143. /* borders of plotting area */
  144. /* computed once on every call to do_plot */
  145. boundary(scaling)
  146.     BOOLEAN scaling;        /* TRUE if terminal is doing the scaling */
  147. {
  148.     register struct termentry *t = &term_tbl[term];
  149.     xleft = (t->h_char)*12;
  150.     xright = (scaling ? 1 : xsize) * (t->xmax) - (t->h_char)*2 - (t->h_tic);
  151.     ybot = (t->v_char)*7/2 + 1;
  152.     ytop = (scaling ? 1 : ysize) * (t->ymax) - (t->v_char)*5/2 - 1;
  153. }
  154.  
  155.  
  156. double dbl_raise(x,y)
  157. double x;
  158. int y;
  159. {
  160. register int i;
  161. double val;
  162.  
  163.     val = 1.0;
  164.     for (i=0; i < abs(y); i++)
  165.         val *= x;
  166.     if (y < 0 ) return (1.0/val);
  167.     return(val);
  168. }
  169.  
  170.  
  171. double make_tics(tmin,tmax,logscale)
  172. double tmin,tmax;
  173. BOOLEAN logscale;
  174. {
  175. register double xr,xnorm,tics,tic,l10;
  176.  
  177.     xr = fabs(tmin-tmax);
  178.     
  179.     l10 = log10(xr);
  180.     if (logscale) {
  181.         tic = dbl_raise(10.0,(l10 >= 0.0 ) ? (int)l10 : ((int)l10-1));
  182.         if (tic < 1.0)
  183.             tic = 1.0;
  184.     } else {
  185.         xnorm = pow(10.0,l10-(double)((l10 >= 0.0 ) ? (int)l10 : ((int)l10-1)));
  186.         if (xnorm <= 2)
  187.             tics = 0.2;
  188.         else if (xnorm <= 5)
  189.             tics = 0.5;
  190.         else tics = 1.0;    
  191.         tic = tics * dbl_raise(10.0,(l10 >= 0.0 ) ? (int)l10 : ((int)l10-1));
  192.     }
  193.     return(tic);
  194. }
  195.  
  196.  
  197. do_plot(plots, pcount, min_x, max_x, min_y, max_y)
  198. struct curve_points *plots;
  199. int pcount;            /* count of plots in linked list */
  200. double min_x, max_x;
  201. double min_y, max_y;
  202. {
  203. register struct termentry *t = &term_tbl[term];
  204. register int curve, xaxis_y, yaxis_x;
  205. register struct curve_points *this_plot;
  206. register double ytic, xtic;
  207. register int xl, yl;
  208.             /* only a Pyramid would have this many registers! */
  209. double xtemp, ytemp;
  210. struct text_label *this_label;
  211. struct arrow_def *this_arrow;
  212. BOOLEAN scaling;
  213.  
  214. /* store these in variables global to this file */
  215. /* otherwise, we have to pass them around a lot */
  216.      x_min = min_x;
  217.      x_max = max_x; 
  218.      y_min = min_y;
  219.      y_max = max_y;
  220.  
  221.     if (polar) {
  222.         /* will possibly change x_min, x_max, y_min, y_max */
  223.         polar_xform(plots,pcount);
  224.     }
  225.  
  226.     if (y_min == VERYLARGE || y_max == -VERYLARGE ||
  227.         x_min == VERYLARGE || x_max == -VERYLARGE)
  228.         int_error("all points undefined!", NO_CARET);
  229.  
  230. /*    Apply the desired viewport offsets. */
  231.      if (y_min < y_max) {
  232.         y_min -= boff;
  233.         y_max += toff;
  234.     } else {
  235.         y_max -= boff;
  236.         y_min += toff;
  237.     }
  238.      if (x_min < x_max) {
  239.         x_min -= loff;
  240.         x_max += roff;
  241.     } else {
  242.         x_max -= loff;
  243.         x_min += roff;
  244.     }
  245.  
  246. /* SETUP RANGES, SCALES AND TIC PLACES */
  247.     if (ytics && yticdef.type == TIC_COMPUTED) {
  248.        ytic = make_tics(y_min,y_max,log_y);
  249.     
  250.        if (autoscale_ly) {
  251.           if (y_min < y_max) {
  252.              y_min = ytic * floor(y_min/ytic);       
  253.              y_max = ytic * ceil(y_max/ytic);
  254.           }
  255.           else {            /* reverse axis */
  256.              y_min = ytic * ceil(y_min/ytic);       
  257.              y_max = ytic * floor(y_max/ytic);
  258.           }
  259.        }
  260.     }
  261.  
  262.     if (xtics && xticdef.type == TIC_COMPUTED) {
  263.        xtic = make_tics(x_min,x_max,log_x);
  264.        
  265.        if (autoscale_lx) {
  266.           if (x_min < x_max) {
  267.              x_min = xtic * floor(x_min/xtic);    
  268.              x_max = xtic * ceil(x_max/xtic);
  269.           } else {
  270.              x_min = xtic * ceil(x_min/xtic);
  271.              x_max = xtic * floor(x_max/xtic);    
  272.           }
  273.        }
  274.     }
  275.  
  276. /*    This used be x_max == x_min, but that caused an infinite loop once. */
  277.     if (fabs(x_max - x_min) < zero)
  278.         int_error("x_min should not equal x_max!",NO_CARET);
  279.     if (fabs(y_max - y_min) < zero)
  280.         int_error("y_min should not equal y_max!",NO_CARET);
  281.  
  282. /* INITIALIZE TERMINAL */
  283.     if (!term_init) {
  284.         (*t->init)();
  285.         term_init = TRUE;
  286.     }
  287.     screen_ok = FALSE;
  288. #ifdef AMIGA_LC_5_1
  289.      scaling = (*t->scale)((double)xsize, (double)ysize);
  290. #else
  291.      scaling = (*t->scale)(xsize, ysize);
  292. #endif
  293.     (*t->graphics)();
  294.  
  295.      /* now compute boundary for plot (xleft, xright, ytop, ybot) */
  296.      boundary(scaling);
  297.  
  298. /* SCALE FACTORS */
  299.     yscale = (ytop - ybot)/(y_max - y_min);
  300.     xscale = (xright - xleft)/(x_max - x_min);
  301.     
  302. /* DRAW AXES */
  303.     (*t->linetype)(-1);    /* axis line type */
  304.     xaxis_y = map_y(0.0);
  305.     yaxis_x = map_x(0.0); 
  306.  
  307.     if (xaxis_y < ybot)
  308.         xaxis_y = ybot;                /* save for impulse plotting */
  309.     else if (xaxis_y >= ytop)
  310.         xaxis_y = ytop ;
  311.     else if (xzeroaxis && !log_y) {
  312.         (*t->move)(xleft,xaxis_y);
  313.         (*t->vector)(xright,xaxis_y);
  314.     }
  315.  
  316.     if (yzeroaxis && !log_x && yaxis_x >= xleft && yaxis_x < xright ) {
  317.         (*t->move)(yaxis_x,ybot);
  318.         (*t->vector)(yaxis_x,ytop);
  319.     }
  320.  
  321. /* DRAW TICS */
  322.     (*t->linetype)(-2); /* border linetype */
  323.  
  324.     /* label y axis tics */
  325.      if (ytics) {
  326.         switch (yticdef.type) {
  327.            case TIC_COMPUTED: {
  328.                if (y_min < y_max)
  329.                 draw_ytics(ytic * floor(y_min/ytic),
  330.                         ytic,
  331.                         ytic * ceil(y_max/ytic));
  332.               else
  333.                 draw_ytics(ytic * floor(y_max/ytic),
  334.                         ytic,
  335.                         ytic * ceil(y_min/ytic));
  336.  
  337.               break;
  338.            }
  339.            case TIC_SERIES: {
  340.               draw_series_ytics(yticdef.def.series.start, 
  341.                             yticdef.def.series.incr, 
  342.                             yticdef.def.series.end);
  343.               break;
  344.            }
  345.            case TIC_USER: {
  346.               draw_set_ytics(yticdef.def.user);
  347.               break;
  348.            }
  349.            default: {
  350.               (*t->text)();
  351.                 (void) fflush(outfile);
  352.               int_error("unknown tic type in yticdef in do_plot", NO_CARET);
  353.               break;        /* NOTREACHED */
  354.            }
  355.         }
  356.     }
  357.  
  358.     /* label x axis tics */
  359.      if (xtics) {
  360.         switch (xticdef.type) {
  361.            case TIC_COMPUTED: {
  362.                if (x_min < x_max)
  363.                 draw_xtics(xtic * floor(x_min/xtic),
  364.                         xtic,
  365.                         xtic * ceil(x_max/xtic));
  366.               else
  367.                 draw_xtics(xtic * floor(x_max/xtic),
  368.                         xtic,
  369.                         xtic * ceil(x_min/xtic));
  370.  
  371.               break;
  372.            }
  373.            case TIC_SERIES: {
  374.               draw_series_xtics(xticdef.def.series.start, 
  375.                             xticdef.def.series.incr, 
  376.                             xticdef.def.series.end);
  377.               break;
  378.            }
  379.            case TIC_USER: {
  380.               draw_set_xtics(xticdef.def.user);
  381.               break;
  382.            }
  383.            default: {
  384.               (*t->text)();
  385.               (void) fflush(outfile);
  386.               int_error("unknown tic type in xticdef in do_plot", NO_CARET);
  387.               break;        /* NOTREACHED */
  388.            }
  389.         }
  390.     }
  391.  
  392. /* DRAW PLOT BORDER */
  393.     (*t->linetype)(-2); /* border linetype */
  394.     if (draw_border) {
  395.         (*t->move)(xleft,ybot);
  396.         (*t->vector)(xright,ybot);
  397.         (*t->vector)(xright,ytop);
  398.         (*t->vector)(xleft,ytop);
  399.         (*t->vector)(xleft,ybot);
  400.     }
  401.  
  402. /* PLACE YLABEL */
  403.     if (strlen(ylabel) > 0) {
  404.         int x, y;
  405.  
  406.         x = ylabel_xoffset * t->h_char;
  407.         y = ylabel_yoffset * t->v_char;
  408.         if ((*t->text_angle)(1)) {
  409.             if ((*t->justify_text)(CENTRE)) {
  410.                 (*t->put_text)(x+(t->v_char),
  411.                          y+(ytop+ybot)/2, ylabel);
  412.             }
  413.             else {
  414.                 (*t->put_text)(x+(t->v_char),
  415.                            y+(ytop+ybot)/2-(t->h_char)*strlen(ylabel)/2, 
  416.                          ylabel);
  417.             }
  418.         }
  419.         else {
  420.             (void)(*t->justify_text)(LEFT);
  421.             (*t->put_text)(x,y+ytop+(t->v_char), ylabel);
  422.         }
  423.         (void)(*t->text_angle)(0);
  424.     }
  425.  
  426. /* PLACE XLABEL */
  427.     if (strlen(xlabel) > 0) {
  428.         int x, y;
  429.  
  430.         x = xlabel_xoffset * t->h_char;
  431.         y = xlabel_yoffset * t->v_char;
  432.  
  433.             if ((*t->justify_text)(CENTRE)) 
  434.             (*t->put_text)(x+(xleft+xright)/2,
  435.                        y+ybot-2*(t->v_char), xlabel);
  436.             else
  437.             (*t->put_text)(x+(xleft+xright)/2 - strlen(xlabel)*(t->h_char)/2,
  438.                            y+ybot-2*(t->v_char), xlabel);
  439.     }
  440.  
  441. /* PLACE TITLE */
  442.     if (strlen(title) > 0) {
  443.         int x, y;
  444.  
  445.         x = title_xoffset * t->h_char;
  446.         y = title_yoffset * t->v_char;
  447.  
  448.             if ((*t->justify_text)(CENTRE))
  449.             (*t->put_text)(x+(xleft+xright)/2,
  450.                        y+ytop+(t->v_char), title);
  451.             else
  452.             (*t->put_text)(x+(xleft+xright)/2 - strlen(title)*(t->h_char)/2,
  453.                        y+ytop+(t->v_char), title);
  454.     }
  455.  
  456.  
  457. /* PLACE TIMEDATE */
  458.     if (timedate) {
  459.         int x, y;
  460.  
  461.         x = time_xoffset * t->h_char;
  462.         y = time_yoffset * t->v_char;
  463.         dated = time( (long *) 0);
  464.         tdate = ctime( &dated);
  465.         tdate[24]='\0';
  466.         if ((*t->text_angle)(1)) {
  467.             if ((*t->justify_text)(CENTRE)) {
  468.                 (*t->put_text)(x+(t->v_char),
  469.                          y+ybot+4*(t->v_char), tdate);
  470.             }
  471.             else {
  472.                 (*t->put_text)(x+(t->v_char),
  473.                          y+ybot+4*(t->v_char)-(t->h_char)*strlen(ylabel)/2, 
  474.                          tdate);
  475.             }
  476.         }
  477.         else {
  478.             (void)(*t->justify_text)(LEFT);
  479.             (*t->put_text)(x,
  480.                          y+ybot-3*(t->v_char), tdate);
  481.         }
  482.         (void)(*t->text_angle)(0);
  483.     }
  484.  
  485. /* PLACE LABELS */
  486.     for (this_label = first_label; this_label!=NULL;
  487.             this_label=this_label->next ) {
  488.          xtemp = LogScale(this_label->x, log_x, "label", "x");
  489.          ytemp = LogScale(this_label->y, log_y, "label", "y");
  490.         if ((*t->justify_text)(this_label->pos)) {
  491.             (*t->put_text)(map_x(xtemp),map_y(ytemp),this_label->text);
  492.         }
  493.         else {
  494.             switch(this_label->pos) {
  495.                 case  LEFT:
  496.                     (*t->put_text)(map_x(xtemp),map_y(ytemp),
  497.                         this_label->text);
  498.                     break;
  499.                 case CENTRE:
  500.                     (*t->put_text)(map_x(xtemp)-
  501.                         (t->h_char)*strlen(this_label->text)/2,
  502.                         map_y(ytemp), this_label->text);
  503.                     break;
  504.                 case RIGHT:
  505.                     (*t->put_text)(map_x(xtemp)-
  506.                         (t->h_char)*strlen(this_label->text),
  507.                         map_y(ytemp), this_label->text);
  508.                     break;
  509.             }
  510.          }
  511.      }
  512.  
  513. /* PLACE ARROWS */
  514.     (*t->linetype)(0);    /* arrow line type */
  515.     for (this_arrow = first_arrow; this_arrow!=NULL;
  516.         this_arrow = this_arrow->next ) {
  517.        int sx = map_x(LogScale(this_arrow->sx, log_x, "arrow", "x"));
  518.        int sy = map_y(LogScale(this_arrow->sy, log_y, "arrow", "y"));
  519.        int ex = map_x(LogScale(this_arrow->ex, log_x, "arrow", "x"));
  520.        int ey = map_y(LogScale(this_arrow->ey, log_y, "arrow", "y"));
  521.        
  522.        (*t->arrow)(sx, sy, ex, ey, this_arrow->head);
  523.     }
  524.  
  525.  
  526. /* DRAW CURVES */
  527.     if (key == -1) {
  528.         xl = xright  - (t->h_tic) - (t->h_char)*5;
  529.         yl = ytop - (t->v_tic) - (t->v_char);
  530.     }
  531.     if (key == 1) {
  532.         xl = map_x( LogScale(key_x, log_x, "key", "x") );
  533.         yl = map_y( LogScale(key_y, log_y, "key", "y") );
  534.     }
  535.  
  536.     this_plot = plots;
  537.     for (curve = 0; curve < pcount; this_plot = this_plot->next_cp, curve++) {
  538.         (*t->linetype)(this_plot->line_type);
  539.         if (key != 0) {
  540.             if ((*t->justify_text)(RIGHT)) {
  541.                 (*t->put_text)(xl,
  542.                     yl,this_plot->title);
  543.             }
  544.             else {
  545.                 if (inrange(xl-(t->h_char)*strlen(this_plot->title), 
  546.                          xleft, xright))
  547.                  (*t->put_text)(xl-(t->h_char)*strlen(this_plot->title),
  548.                              yl,this_plot->title);
  549.             }
  550.         }
  551.  
  552.         switch(this_plot->plot_style) {
  553.             case IMPULSES: {
  554.                if (key != 0) {
  555.                   (*t->move)(xl+(t->h_char),yl);
  556.                   (*t->vector)(xl+4*(t->h_char),yl);
  557.                }
  558.                plot_impulses(this_plot, yaxis_x, xaxis_y);
  559.                break;
  560.             }
  561.             case LINES: {
  562.                if (key != 0) {
  563.                   (*t->move)(xl+(int)(t->h_char),yl);
  564.                   (*t->vector)(xl+(int)(4*(t->h_char)),yl);
  565.                }
  566.                plot_lines(this_plot);
  567.                break;
  568.             }
  569.             case POINTS: {
  570.                if (key != 0) {
  571.                   (*t->point)(xl+2*(t->h_char),yl,
  572.                             this_plot->point_type);
  573.                }
  574.                plot_points(this_plot);
  575.                break;
  576.             }
  577.             case LINESPOINTS: {
  578.                /* put lines */
  579.                if (key != 0) {
  580.                   (*t->move)(xl+(t->h_char),yl);
  581.                   (*t->vector)(xl+4*(t->h_char),yl);
  582.                }
  583.                plot_lines(this_plot);
  584.  
  585.                /* put points */
  586.                if (key != 0) {
  587.                   (*t->point)(xl+2*(t->h_char),yl,
  588.                             this_plot->point_type);
  589.                }
  590.                plot_points(this_plot);
  591.                break;
  592.             }
  593.             case DOTS: {
  594.                if (key != 0) {
  595.                   (*t->point)(xl+2*(t->h_char),yl, -1);
  596.                }
  597.                plot_dots(this_plot);
  598.                break;
  599.             }
  600.             case ERRORBARS: {
  601.                if (key != 0) {
  602.                   (*t->point)(xl+2*(t->h_char),yl,
  603.                             this_plot->point_type);
  604.                }
  605.                plot_points(this_plot);
  606.  
  607.                /* for functions, just like POINTS */
  608.                if (this_plot->plot_type == DATA) {
  609.                   if (key != 0) {
  610.                      (*t->move)(xl+(t->h_char),yl);
  611.                      (*t->vector)(xl+4*(t->h_char),yl);
  612.                      (*t->move)(xl+(t->h_char),yl+ERRORBARTIC);
  613.                      (*t->vector)(xl+(t->h_char),yl-ERRORBARTIC);
  614.                      (*t->move)(xl+4*(t->h_char),yl+ERRORBARTIC);
  615.                      (*t->vector)(xl+4*(t->h_char),yl-ERRORBARTIC);
  616.                   }
  617.                   plot_bars(this_plot);
  618.                }
  619.                break;
  620.             }
  621.         }
  622.         yl = yl - (t->v_char);
  623.     }
  624.     (*t->text)();
  625.     (void) fflush(outfile);
  626. }
  627.  
  628. /* plot_impulses:
  629.  * Plot the curves in IMPULSES style
  630.  */
  631. void
  632. plot_impulses(plot, yaxis_x, xaxis_y)
  633.     struct curve_points *plot;
  634.     int yaxis_x, xaxis_y;
  635. {
  636.     int i;
  637.     int x,y;
  638.     struct termentry *t = &term_tbl[term];
  639.  
  640.     for (i = 0; i < plot->p_count; i++) {
  641.        switch (plot->points[i].type) {
  642.           case INRANGE: {
  643.              x = map_x(plot->points[i].x);
  644.              y = map_y(plot->points[i].y);
  645.              break;
  646.           }
  647.           case OUTRANGE: {
  648.              if (!inrange(plot->points[i].x, x_min,x_max))
  649.                continue;
  650.              x = map_x(plot->points[i].x);
  651.              if ((y_min < y_max 
  652.                  && plot->points[i].y < y_min)
  653.                 || (y_max < y_min 
  654.                     && plot->points[i].y > y_min))
  655.                y = map_y(y_min);
  656.              if ((y_min < y_max 
  657.                  && plot->points[i].y > y_max)
  658.                 || (y_max<y_min 
  659.                     && plot->points[i].y < y_max))
  660.                y = map_y(y_max);
  661.              break;
  662.           }
  663.           default:        /* just a safety */
  664.           case UNDEFINED: {
  665.              continue;
  666.           }
  667.        }
  668.                     
  669.        if (polar)
  670.           (*t->move)(yaxis_x,xaxis_y);
  671.        else
  672.           (*t->move)(x,xaxis_y);
  673.        (*t->vector)(x,y);
  674.     }
  675.  
  676. }
  677.  
  678. /* plot_lines:
  679.  * Plot the curves in LINES style
  680.  */
  681. void
  682. plot_lines(plot)
  683.     struct curve_points *plot;
  684. {
  685.     int i;                /* point index */
  686.     int x,y;                /* point in terminal coordinates */
  687.     struct termentry *t = &term_tbl[term];
  688.     enum coord_type prev = UNDEFINED; /* type of previous point */
  689.     double ex, ey;            /* an edge point */
  690.     double lx[2], ly[2];        /* two edge points */
  691.  
  692.     for (i = 0; i < plot->p_count; i++) {
  693.        switch (plot->points[i].type) {
  694.           case INRANGE: {
  695.              x = map_x(plot->points[i].x);
  696.              y = map_y(plot->points[i].y);
  697.  
  698.              if (prev == INRANGE) {
  699.                 (*t->vector)(x,y);
  700.              } else if (prev == OUTRANGE) {
  701.                 /* from outrange to inrange */
  702.                 if (!clip_lines1) {
  703.                     (*t->move)(x,y);
  704.                 } else {
  705.                     edge_intersect(plot->points, i, &ex, &ey);
  706.                     (*t->move)(map_x(ex), map_y(ey));
  707.                     (*t->vector)(x,y);
  708.                 }
  709.              } else {        /* prev == UNDEFINED */
  710.                 (*t->move)(x,y);
  711.                 (*t->vector)(x,y);
  712.              }
  713.                     
  714.              break;
  715.           }
  716.           case OUTRANGE: {
  717.              if (prev == INRANGE) {
  718.                 /* from inrange to outrange */
  719.                 if (clip_lines1) {
  720.                     edge_intersect(plot->points, i, &ex, &ey);
  721.                     (*t->vector)(map_x(ex), map_y(ey));
  722.                 }
  723.              } else if (prev == OUTRANGE) {
  724.                 /* from outrange to outrange */
  725.                 if (clip_lines2) {
  726.                     if (two_edge_intersect(plot->points, i, lx, ly)) {
  727.                        (*t->move)(map_x(lx[0]), map_y(ly[0]));
  728.                        (*t->vector)(map_x(lx[1]), map_y(ly[1]));
  729.                     }
  730.                 }
  731.              }
  732.              break;
  733.           }
  734.           default:        /* just a safety */
  735.           case UNDEFINED: {
  736.              break;
  737.           }
  738.        }
  739.        prev = plot->points[i].type;
  740.     }
  741. }
  742.  
  743. /* plot_bars:
  744.  * Plot the curves in ERRORBARS style
  745.  *  we just plot the bars; the points are plotted in plot_points
  746.  */
  747. void
  748. plot_bars(plot)
  749.     struct curve_points *plot;
  750. {
  751.     int i;                /* point index */
  752.     struct termentry *t = &term_tbl[term];
  753.     double x;                /* position of the bar */
  754.     double ylow, yhigh;        /* the ends of the bars */
  755.     unsigned int xM, ylowM, yhighM; /* the mapped version of above */
  756.     BOOLEAN low_inrange, high_inrange;
  757.     int tic = ERRORBARTIC;
  758.     
  759.     for (i = 0; i < plot->p_count; i++) {
  760.        /* undefined points don't count */
  761.        if (plot->points[i].type == UNDEFINED)
  762.         continue;
  763.  
  764.        /* check to see if in xrange */
  765.        x = plot->points[i].x;
  766.        if (! inrange(x, x_min, x_max))
  767.         continue;
  768.        xM = map_x(x);
  769.  
  770.        /* find low and high points of bar, and check yrange */
  771.        yhigh = plot->points[i].yhigh;
  772.        ylow = plot->points[i].ylow;
  773.  
  774.        high_inrange = inrange(yhigh, y_min,y_max);
  775.        low_inrange = inrange(ylow, y_min,y_max);
  776.  
  777.        /* compute the plot position of yhigh */
  778.        if (high_inrange)
  779.         yhighM = map_y(yhigh);
  780.        else if (samesign(yhigh-y_max, y_max-y_min))
  781.         yhighM = map_y(y_max);
  782.        else
  783.         yhighM = map_y(y_min);
  784.        
  785.        /* compute the plot position of ylow */
  786.        if (low_inrange)
  787.         ylowM = map_y(ylow);
  788.        else if (samesign(ylow-y_max, y_max-y_min))
  789.         ylowM = map_y(y_max);
  790.        else
  791.         ylowM = map_y(y_min);
  792.  
  793.        if (!high_inrange && !low_inrange && ylowM == yhighM)
  794.         /* both out of range on the same side */
  795.           continue;
  796.  
  797.        /* by here everything has been mapped */
  798.        (*t->move)(xM, ylowM);
  799.        (*t->vector)(xM, yhighM); /* draw the main bar */
  800.        (*t->move)(xM-tic, ylowM); /* draw the bottom tic */
  801.        (*t->vector)(xM+tic, ylowM);
  802.        (*t->move)(xM-tic, yhighM); /* draw the top tic */
  803.        (*t->vector)(xM+tic, yhighM);
  804.     }
  805. }
  806.  
  807. /* plot_points:
  808.  * Plot the curves in POINTS style
  809.  */
  810. void
  811. plot_points(plot)
  812.     struct curve_points *plot;
  813. {
  814.     int i;
  815.     int x,y;
  816.     struct termentry *t = &term_tbl[term];
  817.  
  818.     for (i = 0; i < plot->p_count; i++) {
  819.        if (plot->points[i].type == INRANGE) {
  820.           x = map_x(plot->points[i].x);
  821.           y = map_y(plot->points[i].y);
  822.           /* do clipping if necessary */
  823.           if (!clip_points ||
  824.              (   x >= xleft + t->h_tic  && y >= ybot + t->v_tic 
  825.               && x <= xright - t->h_tic && y <= ytop - t->v_tic))
  826.             (*t->point)(x,y, plot->point_type);
  827.        }
  828.     }
  829. }
  830.  
  831. /* plot_dots:
  832.  * Plot the curves in DOTS style
  833.  */
  834. void
  835. plot_dots(plot)
  836.     struct curve_points *plot;
  837. {
  838.     int i;
  839.     int x,y;
  840.     struct termentry *t = &term_tbl[term];
  841.  
  842.     for (i = 0; i < plot->p_count; i++) {
  843.        if (plot->points[i].type == INRANGE) {
  844.           x = map_x(plot->points[i].x);
  845.           y = map_y(plot->points[i].y);
  846.           /* point type -1 is a dot */
  847.           (*t->point)(x,y, -1);
  848.        }
  849.     }
  850. }
  851.  
  852. /* single edge intersection algorithm */
  853. /* Given two points, one inside and one outside the plot, return
  854.  * the point where an edge of the plot intersects the line segment defined 
  855.  * by the two points.
  856.  */
  857. void
  858. edge_intersect(points, i, ex, ey)
  859.     struct coordinate *points; /* the points array */
  860.     int i;                /* line segment from point i-1 to point i */
  861.     double *ex, *ey;        /* the point where it crosses an edge */
  862. {
  863.     /* global x_min, x_max, y_min, x_max */
  864.     double ax = points[i-1].x;
  865.     double ay = points[i-1].y;
  866.     double bx = points[i].x;
  867.     double by = points[i].y;
  868.     double x, y;            /* possible intersection point */
  869.  
  870.     if (by == ay) {
  871.        /* horizontal line */
  872.        /* assume inrange(by, y_min, y_max) */
  873.        *ey = by;        /* == ay */
  874.  
  875.        if (inrange(x_max, ax, bx))
  876.         *ex = x_max;
  877.        else if (inrange(x_min, ax, bx))
  878.         *ex = x_min;
  879.        else {
  880.         (*term_tbl[term].text)();
  881.         (void) fflush(outfile);
  882.         int_error("error in edge_intersect", NO_CARET);
  883.        }
  884.        return;
  885.     } else if (bx == ax) {
  886.        /* vertical line */
  887.        /* assume inrange(bx, x_min, x_max) */
  888.        *ex = bx;        /* == ax */
  889.  
  890.        if (inrange(y_max, ay, by))
  891.         *ey = y_max;
  892.        else if (inrange(y_min, ay, by))
  893.         *ey = y_min;
  894.        else {
  895.         (*term_tbl[term].text)();
  896.         (void) fflush(outfile);
  897.         int_error("error in edge_intersect", NO_CARET);
  898.        }
  899.        return;
  900.     }
  901.  
  902.     /* slanted line of some kind */
  903.  
  904.     /* does it intersect y_min edge */
  905.     if (inrange(y_min, ay, by) && y_min != ay && y_min != by) {
  906.        x = ax + (y_min-ay) * ((bx-ax) / (by-ay));
  907.        if (inrange(x, x_min, x_max)) {
  908.           *ex = x;
  909.           *ey = y_min;
  910.           return;            /* yes */
  911.        }
  912.     }
  913.     
  914.     /* does it intersect y_max edge */
  915.     if (inrange(y_max, ay, by) && y_max != ay && y_max != by) {
  916.        x = ax + (y_max-ay) * ((bx-ax) / (by-ay));
  917.        if (inrange(x, x_min, x_max)) {
  918.           *ex = x;
  919.           *ey = y_max;
  920.           return;            /* yes */
  921.        }
  922.     }
  923.  
  924.     /* does it intersect x_min edge */
  925.     if (inrange(x_min, ax, bx) && x_min != ax && x_min != bx) {
  926.        y = ay + (x_min-ax) * ((by-ay) / (bx-ax));
  927.        if (inrange(y, y_min, y_max)) {
  928.           *ex = x_min;
  929.           *ey = y;
  930.           return;
  931.        }
  932.     }
  933.  
  934.     /* does it intersect x_max edge */
  935.     if (inrange(x_max, ax, bx) && x_max != ax && x_max != bx) {
  936.        y = ay + (x_max-ax) * ((by-ay) / (bx-ax));
  937.        if (inrange(y, y_min, y_max)) {
  938.           *ex = x_max;
  939.           *ey = y;
  940.           return;
  941.        }
  942.     }
  943.  
  944.     /* It is possible for one or two of the [ab][xy] values to be -VERYLARGE.
  945.     * If ax=bx=-VERYLARGE or ay=by=-VERYLARGE we have already returned 
  946.     * FALSE above. Otherwise we fall through all the tests above. 
  947.     * If two are -VERYLARGE, it is ax=ay=-VERYLARGE or bx=by=-VERYLARGE 
  948.     * since either a or b must be INRANGE. 
  949.     * Note that for ax=ay=-VERYLARGE or bx=by=-VERYLARGE we can do nothing.
  950.     * Handle them carefully here. As yet we have no way for them to be 
  951.     * +VERYLARGE.
  952.     */
  953.     if (ax == -VERYLARGE) {
  954.        if (ay != -VERYLARGE) {
  955.           *ex = min(x_min, x_max);
  956.           *ey = by;
  957.           return;
  958.        }
  959.     } else if (bx == -VERYLARGE) {
  960.        if (by != -VERYLARGE) {
  961.           *ex = min(x_min, x_max);
  962.           *ey = ay;
  963.           return;
  964.        }
  965.     } else if (ay == -VERYLARGE) {
  966.        /* note we know ax != -VERYLARGE */
  967.        *ex = bx;
  968.        *ey = min(y_min, y_max);
  969.        return;
  970.     } else if (by == -VERYLARGE) {
  971.        /* note we know bx != -VERYLARGE */
  972.        *ex = ax;
  973.        *ey = min(y_min, y_max);
  974.        return;
  975.     }
  976.  
  977.     /* If we reach here, then either one point is (-VERYLARGE,-VERYLARGE), 
  978.     * or the inrange point is on the edge, and
  979.      * the line segment from the outrange point does not cross any 
  980.     * other edges to get there. In either case, we return the inrange 
  981.     * point as the 'edge' intersection point. This will basically draw
  982.     * line.
  983.     */
  984.     if (points[i].type == INRANGE) {
  985.        *ex = bx; 
  986.        *ey = by;
  987.     } else {
  988.        *ex = ax; 
  989.        *ey = ay;
  990.     }
  991.     return;
  992. }
  993.  
  994. /* double edge intersection algorithm */
  995. /* Given two points, both outside the plot, return
  996.  * the points where an edge of the plot intersects the line segment defined 
  997.  * by the two points. There may be zero, one, two, or an infinite number
  998.  * of intersection points. (One means an intersection at a corner, infinite
  999.  * means overlaying the edge itself). We return FALSE when there is nothing
  1000.  * to draw (zero intersections), and TRUE when there is something to 
  1001.  * draw (the one-point case is a degenerate of the two-point case and we do 
  1002.  * not distinguish it - we draw it anyway).
  1003.  */
  1004. BOOLEAN                /* any intersection? */
  1005. two_edge_intersect(points, i, lx, ly)
  1006.     struct coordinate *points; /* the points array */
  1007.     int i;                /* line segment from point i-1 to point i */
  1008.     double *lx, *ly;        /* lx[2], ly[2]: points where it crosses edges */
  1009. {
  1010.     /* global x_min, x_max, y_min, x_max */
  1011.     double ax = points[i-1].x;
  1012.     double ay = points[i-1].y;
  1013.     double bx = points[i].x;
  1014.     double by = points[i].y;
  1015.     double x, y;            /* possible intersection point */
  1016.     BOOLEAN intersect = FALSE;
  1017.  
  1018.     if (by == ay) {
  1019.        /* horizontal line */
  1020.        /* y coord must be in range, and line must span both x_min and x_max */
  1021.        /* note that spanning x_min implies spanning x_max */
  1022.        if (inrange(by, y_min, y_max) && inrange(x_min, ax, bx)) {
  1023.           *lx++ = x_min;
  1024.           *ly++ = by;
  1025.           *lx++ = x_max;
  1026.           *ly++ = by;
  1027.           return(TRUE);
  1028.        } else
  1029.         return(FALSE);
  1030.     } else if (bx == ax) {
  1031.        /* vertical line */
  1032.        /* x coord must be in range, and line must span both y_min and y_max */
  1033.        /* note that spanning y_min implies spanning y_max */
  1034.        if (inrange(bx, x_min, x_max) && inrange(y_min, ay, by)) {
  1035.           *lx++ = bx;
  1036.           *ly++ = y_min;
  1037.           *lx++ = bx;
  1038.           *ly++ = y_max;
  1039.           return(TRUE);
  1040.        } else
  1041.         return(FALSE);
  1042.     }
  1043.  
  1044.     /* slanted line of some kind */
  1045.     /* there can be only zero or two intersections below */
  1046.  
  1047.     /* does it intersect y_min edge */
  1048.     if (inrange(y_min, ay, by)) {
  1049.        x = ax + (y_min-ay) * ((bx-ax) / (by-ay));
  1050.        if (inrange(x, x_min, x_max)) {
  1051.           *lx++ = x;
  1052.           *ly++ = y_min;
  1053.           intersect = TRUE;
  1054.        }
  1055.     }
  1056.     
  1057.     /* does it intersect y_max edge */
  1058.     if (inrange(y_max, ay, by)) {
  1059.        x = ax + (y_max-ay) * ((bx-ax) / (by-ay));
  1060.        if (inrange(x, x_min, x_max)) {
  1061.           *lx++ = x;
  1062.           *ly++ = y_max;
  1063.           intersect = TRUE;
  1064.        }
  1065.     }
  1066.  
  1067.     /* does it intersect x_min edge */
  1068.     if (inrange(x_min, ax, bx)) {
  1069.        y = ay + (x_min-ax) * ((by-ay) / (bx-ax));
  1070.        if (inrange(y, y_min, y_max)) {
  1071.           *lx++ = x_min;
  1072.           *ly++ = y;
  1073.           intersect = TRUE;
  1074.        }
  1075.     }
  1076.  
  1077.     /* does it intersect x_max edge */
  1078.     if (inrange(x_max, ax, bx)) {
  1079.        y = ay + (x_max-ax) * ((by-ay) / (bx-ax));
  1080.        if (inrange(y, y_min, y_max)) {
  1081.           *lx++ = x_max;
  1082.           *ly++ = y;
  1083.           intersect = TRUE;
  1084.        }
  1085.     }
  1086.  
  1087.     if (intersect)
  1088.      return(TRUE);
  1089.  
  1090.     /* It is possible for one or more of the [ab][xy] values to be -VERYLARGE.
  1091.     * If ax=bx=-VERYLARGE or ay=by=-VERYLARGE we have already returned
  1092.     * FALSE above.
  1093.     * Note that for ax=ay=-VERYLARGE or bx=by=-VERYLARGE we can do nothing.
  1094.     * Otherwise we fall through all the tests above. 
  1095.     * Handle them carefully here. As yet we have no way for them to be +VERYLARGE.
  1096.     */
  1097.     if (ax == -VERYLARGE) {
  1098.        if (ay != -VERYLARGE
  1099.           && inrange(by, y_min, y_max) && inrange(x_max, ax, bx)) {
  1100.           *lx++ = x_min;
  1101.           *ly = by;
  1102.           *lx++ = x_max;
  1103.           *ly = by;
  1104.           intersect = TRUE;
  1105.        }
  1106.     } else if (bx == -VERYLARGE) {
  1107.        if (by != -VERYLARGE
  1108.           && inrange(ay, y_min, y_max) && inrange(x_max, ax, bx)) {
  1109.           *lx++ = x_min;
  1110.           *ly = ay;
  1111.           *lx++ = x_max;
  1112.           *ly = ay;
  1113.           intersect = TRUE;
  1114.        }
  1115.     } else if (ay == -VERYLARGE) {
  1116.        /* note we know ax != -VERYLARGE */
  1117.        if (inrange(bx, x_min, x_max) && inrange(y_max, ay, by)) {
  1118.           *lx++ = bx;
  1119.           *ly = y_min;
  1120.           *lx++ = bx;
  1121.           *ly = y_max;
  1122.           intersect = TRUE;
  1123.        }
  1124.     } else if (by == -VERYLARGE) {
  1125.        /* note we know bx != -VERYLARGE */
  1126.        if (inrange(ax, x_min, x_max) && inrange(y_max, ay, by)) {
  1127.           *lx++ = ax;
  1128.           *ly = y_min;
  1129.           *lx++ = ax;
  1130.           *ly = y_max;
  1131.           intersect = TRUE;
  1132.        }
  1133.     }
  1134.  
  1135.     return(intersect);
  1136. }
  1137.  
  1138. /* Polar transform of all curves */
  1139. /* Original code by John Campbell (CAMPBELL@NAUVAX.bitnet) */
  1140. polar_xform (plots, pcount)
  1141.     struct curve_points *plots;
  1142.     int pcount;            /* count of curves in plots array */
  1143. {
  1144.      struct curve_points *this_plot;
  1145.      int curve;            /* loop var, for curves */
  1146.      register int i, p_cnt;    /* loop/limit var, for points */
  1147.      struct coordinate *pnts;    /* abbrev. for points array */
  1148.     double x, y;            /* new cartesian value */
  1149.     BOOLEAN anydefined = FALSE;
  1150.     double d2r;
  1151.  
  1152.     if(angles_format == ANGLES_DEGREES){
  1153.         d2r = DEG2RAD;
  1154.     } else {
  1155.         d2r = 1.0;
  1156.     }
  1157.  
  1158. /*
  1159.     Cycle through all the plots converting polar to rectangular.
  1160.      If autoscaling, adjust max and mins. Ignore previous values.
  1161.     If not autoscaling, use the yrange for both x and y ranges.
  1162. */
  1163.     if (autoscale_ly) {
  1164.         x_min = VERYLARGE;
  1165.         y_min = VERYLARGE;
  1166.         x_max = -VERYLARGE;
  1167.         y_max = -VERYLARGE;
  1168.         autoscale_lx = TRUE;
  1169.     } else {
  1170.         x_min = y_min;
  1171.         x_max = y_max;
  1172.     }
  1173.     
  1174.     this_plot = plots;
  1175.     for (curve = 0; curve < pcount; this_plot = this_plot->next_cp, curve++) {
  1176.         p_cnt = this_plot->p_count;
  1177.         pnts = &(this_plot->points[0]);
  1178.  
  1179.     /*    Convert to cartesian all points in this curve. */
  1180.         for (i = 0; i < p_cnt; i++) {
  1181.             if (pnts[i].type != UNDEFINED) {
  1182.                  anydefined = TRUE;
  1183.                  /* modify points to reset origin and from degrees */
  1184.                  pnts[i].y -= rmin;
  1185.                  pnts[i].x *= d2r;
  1186.                  /* convert to cartesian coordinates */
  1187.                 x = pnts[i].y*cos(pnts[i].x);
  1188.                 y = pnts[i].y*sin(pnts[i].x);
  1189.                 pnts[i].x = x;
  1190.                 pnts[i].y = y;
  1191.                 if (autoscale_ly) {
  1192.                     if (x_min > x) x_min = x;
  1193.                     if (x_max < x) x_max = x;
  1194.                     if (y_min > y) y_min = y;
  1195.                     if (y_max < y) y_max = y;
  1196.                     pnts[i].type = INRANGE;
  1197.                 } else if(inrange(x, x_min, x_max) && inrange(y, y_min, y_max))
  1198.                   pnts[i].type = INRANGE;
  1199.                 else
  1200.                   pnts[i].type = OUTRANGE;
  1201.             }
  1202.         }    
  1203.     }
  1204.  
  1205.     if (autoscale_lx && anydefined && fabs(x_max - x_min) < zero) {
  1206.         /* This happens at least for the plot of 1/cos(x) (vertical line). */
  1207.         fprintf(stderr, "Warning: empty x range [%g:%g], ", x_min,x_max);
  1208.         if (x_min == 0.0) {
  1209.            x_min = -1; 
  1210.            x_max = 1;
  1211.         } else {
  1212.            x_min *= 0.9;
  1213.            x_max *= 1.1;
  1214.         }
  1215.         fprintf(stderr, "adjusting to [%g:%g]\n", x_min,x_max);
  1216.     }
  1217.     if (autoscale_ly && anydefined && fabs(y_max - y_min) < zero) {
  1218.         /* This happens at least for the plot of 1/sin(x) (horiz. line). */
  1219.         fprintf(stderr, "Warning: empty y range [%g:%g], ", y_min, y_max);
  1220.         if (y_min == 0.0) {
  1221.            y_min = -1;
  1222.            y_max = 1;
  1223.         } else {
  1224.            y_min *= 0.9;
  1225.            y_max *= 1.1;
  1226.         }
  1227.         fprintf(stderr, "adjusting to [%g:%g]\n", y_min, y_max);
  1228.     }
  1229. }
  1230.  
  1231. /* DRAW_YTICS: draw a regular tic series, y axis */
  1232. draw_ytics(start, incr, end)
  1233.         double start, incr, end; /* tic series definition */
  1234.         /* assume start < end, incr > 0 */
  1235. {
  1236.     double ticplace;
  1237.     int ltic;            /* for mini log tics */
  1238.     double lticplace;    /* for mini log tics */
  1239.     double ticmin, ticmax;    /* for checking if tic is almost inrange */
  1240.  
  1241.     if (end == VERYLARGE)            /* for user-def series */
  1242.         end = max(y_min,y_max);
  1243.  
  1244.     /* limit to right side of plot */
  1245.     end = min(end, max(y_min,y_max));
  1246.  
  1247.     /* to allow for rounding errors */
  1248.     ticmin = min(y_min,y_max) - SIGNIF*incr;
  1249.     ticmax = max(y_min,y_max) + SIGNIF*incr;
  1250.     end = end + SIGNIF*incr; 
  1251.  
  1252.     for (ticplace = start; ticplace <= end; ticplace +=incr) {
  1253.         if ( inrange(ticplace,ticmin,ticmax) )
  1254.             ytick(ticplace, yformat, incr, 1.0);
  1255.         if (log_y && incr == 1.0) {
  1256.             /* add mini-ticks to log scale ticmarks */
  1257.             int lstart, linc;
  1258.             if ((end - start) >= 10)
  1259.             {
  1260.             lstart = 10; /* No little ticks */
  1261.             linc = 5;
  1262.             }
  1263.             else if((end - start) >= 5)
  1264.             {
  1265.             lstart = 4; /* 3 per decade */
  1266.             linc = 3;
  1267.             }
  1268.             else
  1269.             {
  1270.             lstart = 2; /* 9 per decade */
  1271.             linc = 1;
  1272.             }
  1273.             for (ltic = 2; ltic <= 9; ltic++) {
  1274.                 lticplace = ticplace+log10((double)ltic);
  1275.                 if ( inrange(lticplace,ticmin,ticmax) )
  1276.                     ytick(lticplace, "\0", incr, 0.5);
  1277.             }
  1278.         }
  1279.     }
  1280. }
  1281.  
  1282. /* DRAW_XTICS: draw a regular tic series, x axis */
  1283. draw_xtics(start, incr, end)
  1284.         double start, incr, end; /* tic series definition */
  1285.         /* assume start < end, incr > 0 */
  1286. {
  1287.     double ticplace;
  1288.     int ltic;            /* for mini log tics */
  1289.     double lticplace;    /* for mini log tics */
  1290.     double ticmin, ticmax;    /* for checking if tic is almost inrange */
  1291.  
  1292.     if (end == VERYLARGE)            /* for user-def series */
  1293.         end = max(x_min,x_max);
  1294.  
  1295.     /* limit to right side of plot */
  1296.     end = min(end, max(x_min,x_max));
  1297.  
  1298.     /* to allow for rounding errors */
  1299.     ticmin = min(x_min,x_max) - SIGNIF*incr;
  1300.     ticmax = max(x_min,x_max) + SIGNIF*incr;
  1301.     end = end + SIGNIF*incr; 
  1302.  
  1303.     for (ticplace = start; ticplace <= end; ticplace +=incr) {
  1304.         if ( inrange(ticplace,ticmin,ticmax) )
  1305.             xtick(ticplace, xformat, incr, 1.0);
  1306.         if (log_x && incr == 1.0) {
  1307.             /* add mini-ticks to log scale ticmarks */
  1308.             int lstart, linc;
  1309.             if ((end - start) >= 10)
  1310.             {
  1311.             lstart = 10; /* No little ticks */
  1312.             linc = 5;
  1313.             }
  1314.             else if((end - start) >= 5)
  1315.             {
  1316.             lstart = 4; /* 3 per decade */
  1317.             linc = 3;
  1318.             }
  1319.             else
  1320.             {
  1321.             lstart = 2; /* 9 per decade */
  1322.             linc = 1;
  1323.             }
  1324.             for (ltic = lstart; ltic <= 9; ltic += linc) {
  1325.                 lticplace = ticplace+log10((double)ltic);
  1326.                 if ( inrange(lticplace,ticmin,ticmax) )
  1327.                     xtick(lticplace, "\0", incr, 0.5);
  1328.             }
  1329.         }
  1330.     }
  1331. }
  1332.  
  1333. /* DRAW_SERIES_YTICS: draw a user tic series, y axis */
  1334. draw_series_ytics(start, incr, end)
  1335.         double start, incr, end; /* tic series definition */
  1336.         /* assume start < end, incr > 0 */
  1337. {
  1338.     double ticplace, place;
  1339.     double ticmin, ticmax;    /* for checking if tic is almost inrange */
  1340.     double spacing = log_y ? log10(incr) : incr;
  1341.  
  1342.     if (end == VERYLARGE)
  1343.         end = max(CheckLog(log_y, y_min), CheckLog(log_y, y_max));
  1344.     else
  1345.       /* limit to right side of plot */
  1346.       end = min(end, max(CheckLog(log_y, y_min), CheckLog(log_y, y_max)));
  1347.  
  1348.     /* to allow for rounding errors */
  1349.     ticmin = min(y_min,y_max) - SIGNIF*incr;
  1350.     ticmax = max(y_min,y_max) + SIGNIF*incr;
  1351.     end = end + SIGNIF*incr; 
  1352.  
  1353.     for (ticplace = start; ticplace <= end; ticplace +=incr) {
  1354.         place = (log_y ? log10(ticplace) : ticplace);
  1355.         if ( inrange(place,ticmin,ticmax) )
  1356.          ytick(place, yformat, spacing, 1.0);
  1357.     }
  1358. }
  1359.  
  1360.  
  1361. /* DRAW_SERIES_XTICS: draw a user tic series, x axis */
  1362. draw_series_xtics(start, incr, end)
  1363.         double start, incr, end; /* tic series definition */
  1364.         /* assume start < end, incr > 0 */
  1365. {
  1366.     double ticplace, place;
  1367.     double ticmin, ticmax;    /* for checking if tic is almost inrange */
  1368.     double spacing = log_x ? log10(incr) : incr;
  1369.  
  1370.     if (end == VERYLARGE)
  1371.         end = max(CheckLog(log_x, x_min), CheckLog(log_x, x_max));
  1372.     else
  1373.       /* limit to right side of plot */
  1374.       end = min(end, max(CheckLog(log_x, x_min), CheckLog(log_x, x_max)));
  1375.  
  1376.     /* to allow for rounding errors */
  1377.     ticmin = min(x_min,x_max) - SIGNIF*incr;
  1378.     ticmax = max(x_min,x_max) + SIGNIF*incr;
  1379.     end = end + SIGNIF*incr; 
  1380.  
  1381.     for (ticplace = start; ticplace <= end; ticplace +=incr) {
  1382.         place = (log_x ? log10(ticplace) : ticplace);
  1383.         if ( inrange(place,ticmin,ticmax) )
  1384.          xtick(place, xformat, spacing, 1.0);
  1385.     }
  1386. }
  1387.  
  1388. /* DRAW_SET_YTICS: draw a user tic set, y axis */
  1389. draw_set_ytics(list)
  1390.     struct ticmark *list;    /* list of tic marks */
  1391. {
  1392.     double ticplace;
  1393.     double incr = (y_max - y_min) / 10;
  1394.     /* global x_min, x_max, xscale, y_min, y_max, yscale */
  1395.  
  1396.     while (list != NULL) {
  1397.        ticplace = (log_y ? log10(list->position) : list->position);
  1398.        if ( inrange(ticplace, y_min, y_max)         /* in range */
  1399.           || NearlyEqual(ticplace, y_min, incr)    /* == y_min */
  1400.           || NearlyEqual(ticplace, y_max, incr))    /* == y_max */
  1401.         ytick(ticplace, list->label, incr, 1.0);
  1402.  
  1403.        list = list->next;
  1404.     }
  1405. }
  1406.  
  1407. /* DRAW_SET_XTICS: draw a user tic set, x axis */
  1408. draw_set_xtics(list)
  1409.     struct ticmark *list;    /* list of tic marks */
  1410. {
  1411.     double ticplace;
  1412.     double incr = (x_max - x_min) / 10;
  1413.     /* global x_min, x_max, xscale, y_min, y_max, yscale */
  1414.  
  1415.     while (list != NULL) {
  1416.        ticplace = (log_x ? log10(list->position) : list->position);
  1417.        if ( inrange(ticplace, x_min, x_max)         /* in range */
  1418.           || NearlyEqual(ticplace, x_min, incr)    /* == x_min */
  1419.           || NearlyEqual(ticplace, x_max, incr))    /* == x_max */
  1420.         xtick(ticplace, list->label, incr, 1.0);
  1421.  
  1422.        list = list->next;
  1423.     }
  1424. }
  1425.  
  1426. /* draw and label a y-axis ticmark */
  1427. ytick(place, text, spacing, ticscale)
  1428.         double place;                   /* where on axis to put it */
  1429.         char *text;                     /* optional text label */
  1430.         double spacing;         /* something to use with checkzero */
  1431.         double ticscale;         /* scale factor for tic mark (0..1] */
  1432. {
  1433.     register struct termentry *t = &term_tbl[term];
  1434.     char ticlabel[101];
  1435.     int ticsize = (int)((t->h_tic) * ticscale);
  1436.  
  1437.     place = CheckZero(place,spacing); /* to fix rounding error near zero */
  1438.     if (grid) {
  1439.            (*t->linetype)(-1);  /* axis line type */
  1440.            /* do not put a rectangular grid on a polar plot */
  1441.        if( !polar){
  1442.          (*t->move)(xleft, map_y(place));
  1443.          (*t->vector)(xright, map_y(place));
  1444.            }
  1445.        (*t->linetype)(-2); /* border linetype */
  1446.     }
  1447.     if (tic_in) {
  1448.       /* if polar plot, put the tics along the axes */
  1449.       if( polar){
  1450.            (*t->move)(map_x(ZERO),map_y(place));
  1451.            (*t->vector)(map_x(ZERO) + ticsize, map_y(place));
  1452.            (*t->move)(map_x(ZERO), map_y(place));
  1453.            (*t->vector)(map_x(ZERO) - ticsize, map_y(place));
  1454.      } else {
  1455.        (*t->move)(xleft, map_y(place));
  1456.            (*t->vector)(xleft + ticsize, map_y(place));
  1457.            (*t->move)(xright, map_y(place));
  1458.            (*t->vector)(xright - ticsize, map_y(place));
  1459.      }
  1460.     } else {
  1461.       if( polar){
  1462.            (*t->move)(map_x(ZERO), map_y(place));
  1463.            (*t->vector)(map_x(ZERO) - ticsize, map_y(place));
  1464.      }else{
  1465.            (*t->move)(xleft, map_y(place));
  1466.            (*t->vector)(xleft - ticsize, map_y(place));
  1467.      }
  1468.     }
  1469.  
  1470.     /* label the ticmark */
  1471.     if (text == NULL) 
  1472.      text = yformat;
  1473.     
  1474.     if( polar){
  1475.       (void) sprintf(ticlabel, text, CheckLog(log_y,fabs( place)+rmin));
  1476.       if ((*t->justify_text)(RIGHT)) {
  1477.        (*t->put_text)(map_x(ZERO)-(t->h_char),
  1478.                    map_y(place), ticlabel);
  1479.      } else {
  1480.        (*t->put_text)(map_x(ZERO)-(t->h_char)*(strlen(ticlabel)+1),
  1481.                    map_y(place), ticlabel);
  1482.      }
  1483.     } else {
  1484.     
  1485.       (void) sprintf(ticlabel, text, CheckLog(log_y, place));
  1486.       if ((*t->justify_text)(RIGHT)) {
  1487.        (*t->put_text)(xleft-(t->h_char),
  1488.                    map_y(place), ticlabel);
  1489.      } else {
  1490.        (*t->put_text)(xleft-(t->h_char)*(strlen(ticlabel)+1),
  1491.                    map_y(place), ticlabel);
  1492.      }
  1493.     }
  1494. }
  1495.  
  1496. /* draw and label an x-axis ticmark */
  1497. xtick(place, text, spacing, ticscale)
  1498.         double place;                   /* where on axis to put it */
  1499.         char *text;                     /* optional text label */
  1500.         double spacing;         /* something to use with checkzero */
  1501.         double ticscale;         /* scale factor for tic mark (0..1] */
  1502. {
  1503.     register struct termentry *t = &term_tbl[term];
  1504.     char ticlabel[101];
  1505.     int ticsize = (int)((t->v_tic) * ticscale);
  1506.  
  1507.     place = CheckZero(place,spacing); /* to fix rounding error near zero */
  1508.     if (grid) {
  1509.            (*t->linetype)(-1);  /* axis line type */
  1510.            if( !polar){
  1511.          (*t->move)(map_x(place), ybot);
  1512.          (*t->vector)(map_x(place), ytop);
  1513.            }
  1514.        (*t->linetype)(-2); /* border linetype */
  1515.     }
  1516.     if (tic_in) {
  1517.       if( polar){
  1518.            (*t->move)(map_x(place), map_y(ZERO));
  1519.            (*t->vector)(map_x(place), map_y(ZERO) + ticsize);
  1520.            (*t->move)(map_x(place), map_y(ZERO));
  1521.            (*t->vector)(map_x(place), map_y(ZERO) - ticsize);
  1522.      } else{
  1523.            (*t->move)(map_x(place), ybot);
  1524.            (*t->vector)(map_x(place), ybot + ticsize);
  1525.            (*t->move)(map_x(place), ytop);
  1526.            (*t->vector)(map_x(place), ytop - ticsize);
  1527.      }
  1528.     } else {
  1529.       if( polar){
  1530.            (*t->move)(map_x(place), map_y(ZERO));
  1531.            (*t->vector)(map_x(place), map_y(ZERO) - ticsize);
  1532.      }else{
  1533.            (*t->move)(map_x(place), ybot);
  1534.            (*t->vector)(map_x(place), ybot - ticsize);
  1535.      }
  1536.     }
  1537.     
  1538.     /* label the ticmark */
  1539.     if (text == NULL)
  1540.      text = xformat;
  1541.  
  1542.     if(polar){
  1543.       (void) sprintf(ticlabel, text, CheckLog(log_x, fabs(place)+rmin));
  1544.       if ((*t->justify_text)(CENTRE)) {
  1545.        (*t->put_text)(map_x(place),
  1546.                    map_y(ZERO)-(t->v_char), ticlabel);
  1547.      } else {
  1548.        (*t->put_text)(map_x(place)-(t->h_char)*strlen(ticlabel)/2,
  1549.                    map_y(ZERO)-(t->v_char), ticlabel);
  1550.      }
  1551.     }else{
  1552.  
  1553.       (void) sprintf(ticlabel, text, CheckLog(log_x, place));
  1554.       if ((*t->justify_text)(CENTRE)) {
  1555.        (*t->put_text)(map_x(place),
  1556.                    ybot-(t->v_char), ticlabel);
  1557.      } else {
  1558.        (*t->put_text)(map_x(place)-(t->h_char)*strlen(ticlabel)/2,
  1559.                    ybot-(t->v_char), ticlabel);
  1560.      }
  1561.     }
  1562. }
  1563.